#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <fcntl.h>


#define FD_LEN       128
#define EVENT_SIZE   1024
#define LISTEN_QSIZE 10
#define BUFFER_SIZE  1024
#define TIMEOUT      5000
#define PORT         9876


int main( int argc, char **argv )
{
	int result, i, client_len, read_num, c, fd;
	int serverfd, clientfd;
	int epoll_fd;
	struct epoll_event event[EVENT_SIZE], reg_event;
	struct sockaddr_in server_addr, client_addr;
	char buffer[BUFFER_SIZE], sendbuf[BUFFER_SIZE];
	FILE *fildes;

	/* create epoll file descriptor */
	epoll_fd = epoll_create( 10 );

	/* create server socket */
	serverfd                    = socket( AF_INET, SOCK_STREAM, 0 );
	server_addr.sin_family      = AF_INET;
	server_addr.sin_addr.s_addr = htonl( INADDR_ANY );
	server_addr.sin_port        = htons( PORT );


	/* associate the server socket fd with epoll_fd */
	reg_event.events            = EPOLLIN | EPOLLHUP | EPOLLERR;
	reg_event.data.fd           = serverfd;
	fcntl( serverfd, F_SETFL, (fcntl( serverfd, F_GETFL, 0 ) | O_NONBLOCK));
	epoll_ctl( epoll_fd, EPOLL_CTL_ADD, serverfd, &reg_event );

	/* begin to listen */
	bind( serverfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	listen( serverfd, LISTEN_QSIZE );

	while( 1 ) {
		/* wait for event */
		result = epoll_wait( epoll_fd, (struct epoll_event *)event, EVENT_SIZE, TIMEOUT );

		if( result ) {
			for( i = 0; i < result; i++ ) {
				/* client connect to server */
				if( event[i].data.fd == serverfd ) {
					client_len = sizeof(client_addr);
					clientfd = accept( serverfd,
							(struct sockaddr *)&client_addr,
							(socklen_t *)&client_len );
					reg_event.events  = EPOLLIN | EPOLLHUP | EPOLLERR;
					reg_event.data.fd = clientfd;
					fcntl( clientfd, F_SETFL,
							(fcntl( clientfd, F_GETFL, 0 ) | O_NONBLOCK));
					epoll_ctl( epoll_fd, EPOLL_CTL_ADD, clientfd, &reg_event );
				}
				else {
					/* data transmission */
					if( event[i].events & EPOLLIN ) {
						clientfd = event[i].data.fd;

						//ioctl(clientfd,FIONREAD,&nread);
						read_num = read( clientfd, buffer, BUFFER_SIZE );
						if( read_num > 0 ) {
							//printf("%s\n",buffer);
							reg_event.events = EPOLLOUT | EPOLLET;
							reg_event.data.fd = clientfd;
							epoll_ctl( epoll_fd, EPOLL_CTL_MOD, clientfd, &reg_event );
						}
						else {
							perror( "read from client fd failed.\n" );
						}

					}
					if( event[i].events & (EPOLLHUP | EPOLLERR)) {
						epoll_ctl( epoll_fd, EPOLL_CTL_DEL, event[i].data.fd, NULL );
						perror( "epollhup | epollerr\n" );
					}
					if( event[i].events & EPOLLOUT ) {
						if( strncmp( buffer, "GET", 3 ) == 0 ) {
							/* send mypage.htm to client */
							clientfd = event[i].data.fd;

							if((fd = open( "mypage.htm", O_RDONLY )) < 0 ) {
								perror( "mypage.htm" );
							}

							while((c = read( fd, sendbuf, BUFFER_SIZE )) > 0 ) {
								write( clientfd, sendbuf, strlen( sendbuf ));
								//printf("%s",sendbuf);
								memset( sendbuf, 0, BUFFER_SIZE );
							}
							close( fd );
							/* finish current connection , close client */
							epoll_ctl( epoll_fd, EPOLL_CTL_DEL, clientfd, NULL );
							memset( buffer, 0, BUFFER_SIZE );
							close( clientfd );
						}
						//printf("ok\n");
					}
				}
			}
		}
		else if( result == -1 ) {
			/* error */
			perror( "epoll_wait\n" );
		}
		else {
			/* timeout,do nothing */
			//perror("timeout\n");
		}
	}

	close( epoll_fd );
	exit( 0 );
}
